/*
 * --------------------------------------------------------------------
 * @name BasicNode.java
 * @author Juan Camilo Ibarra
 *
 * This work is licensed under a Creative
 * Commons Attribution 3.0 License. This means you can to copy, 
 * distribute, transmit and adapt the work, under the following condition:
 * You must attribute the work in the manner specified by the author or licensor.
 *
 * Juan Camilo Ibarra	-	ju-ibarr@uniandes.edu.co
 *
 * IMAGINE research group
 * Universidad de los Andes
 * Sep 12, 2011
 * --------------------------------------------------------------------
 */
package render;

import java.awt.Font;

import javax.media.j3d.Appearance;
import javax.media.j3d.Billboard;
import javax.media.j3d.Bounds;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.Group;
import javax.media.j3d.LineArray;
import javax.media.j3d.Node;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.AxisAngle4d;
import javax.vecmath.Color3f;
import javax.vecmath.Matrix3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.geometry.Text2D;

/**
 * Is the basic node for the Representation system
 * @author juanibarral
 *
 */
public abstract class NodeCharacteristics {


	public static final String GROUP_TRANSFORMATION_NAME = "GROUP_TRANSFORMATION";
	public static final String INTERPOLATION_TG_NAME = "INTERPOLATION_TRANSFORM_GROUP";
	public static final String GROUP_INTERPOLATORS_NAME = "GROUP_INTERPOLATORS";
	public static final String SCALE_INTERPOLATOR_NAME = "SCALE_INTERPOLATOR";
	public static final String APPEARANCE_INTERPOLATOR_NAME = "APPEARANCE_INTERPOLATOR";
	public static final String COLOR_INTERPOLATOR_NAME = "COLOR_INTERPOLATOR";
	public static final String CUSTOM_INTERPOLATOR_NAME = "CUSTOM_INTERPOLATOR";
	public static final String POSITION_INTERPOLATOR_NAME = "POSITION_INTERPOLATOR";
	
	

	/**
	 * Get the transformation group for the given parameters
	 * @param position position
	 * @param rotation rotation
	 * @param scale scale
	 * @return
	 */
	public static TransformGroup getTransformGroup(Vector3f position, Matrix3d rotation, double scale)
	{
		TransformGroup transformationGroup= new TransformGroup();
		
		setTransformGroupCapabilites(transformationGroup);
		transformationGroup.setUserData(GROUP_TRANSFORMATION_NAME);		
		Transform3D transform = new Transform3D();
		transform.setRotation(rotation);
		transform.setTranslation(position);
		transform.setScale(scale);
		transformationGroup.setTransform(transform);
		return transformationGroup;
	}


	
	/**
	 * Creates a text over a geometry (Font helvetica, 24, Bold)
	 * @param bounds bounds for the billboard capacity (always look at the camera)
	 * @param offset distance between teh object's center and the text
	 * @param size size of the text in visual units
	 * @param name string to be rendered
	 * @return
	 */
	public static BranchGroup createTextBranchGroup(Bounds bounds, double offset, double size, String name, Color3f textColor)
	{
		int fontSize = 96;
		//The scale factor is 1/256 by default, so a 12pt font is 12/256 = 0.047 mts 
		float textScaleFactor = (float)size / (float)fontSize;
		BranchGroup bgText = new BranchGroup();
		bgText.setUserData("TEXT");
		setBranchGroupCapabilities(bgText);
		
		Transform3D t3dText = new Transform3D();
		t3dText.setTranslation(new Vector3d(0.0, 0.0, offset));
		t3dText.setRotation(new AxisAngle4d(1.0, 0.0, 0.0, Math.toRadians(90)));
		
		TransformGroup tgText = new TransformGroup(t3dText);
		tgText.setUserData("TG_TEXT");
		setTransformGroupCapabilites(tgText);
		
		Text2D text = new Text2D(name, textColor, "Helvetica", fontSize, Font.BOLD);
		setShape3DCapabilites(text);
		text.setPickable(true);
//		text.setCapability(Geometry.ALLOW_INTERSECT);
		text.setRectangleScaleFactor(textScaleFactor);
		
		Point3f[] plaPts = new Point3f[2];
	    plaPts[0] = new Point3f(0.0f, 0.0f, 0.0f);
	    plaPts[1] = new Point3f(0.0f, 0.0f, (float)offset);
	    LineArray pla = new LineArray(2, LineArray.COORDINATES);
	    pla.setCoordinates(0, plaPts);
	    Appearance app = new Appearance();
	    ColoringAttributes ca = new ColoringAttributes(textColor, ColoringAttributes.SHADE_FLAT);
	    app.setColoringAttributes(ca);
	    Shape3D lineShape = new Shape3D(pla, app);
	    setShape3DCapabilites(lineShape);
	    bgText.addChild(lineShape);
		
		bgText.addChild(tgText);
		
		TransformGroup tgBillboard = new TransformGroup(new Transform3D());
		tgBillboard.setUserData("TG_BILLBOARD");
		setTransformGroupCapabilites(tgBillboard);
		tgText.addChild(tgBillboard);
		tgBillboard.addChild(text);
		Billboard billboard = new Billboard(tgBillboard, Billboard.ROTATE_ABOUT_POINT, new Point3f());
		billboard.setSchedulingBounds(bounds);
		bgText.addChild(billboard);
		
		return bgText;
	}
	
	/**
	 * Creates a text over a geometry 
	 * @param bounds
	 * @param position position of the text
	 * @param size size of the text in visualization units
	 * @param name string to be rendered
	 * @param textColor color of the text
	 * @return
	 */
	public static BranchGroup createTextBranchGroup(Bounds bounds, double[] position, double size, String name, Color3f textColor)
	{
		int fontSize = 96;
		//The scale factor is 1/256 by default, so a 12pt font is 12/256 = 0.047 mts 
		float textScaleFactor = (float)size / (float)fontSize;
		BranchGroup bgText = new BranchGroup();
		bgText.setUserData("TEXT");
		setBranchGroupCapabilities(bgText);
		
		Transform3D t3dText = new Transform3D();
		t3dText.setTranslation(new Vector3d(position[0], position[1], position[2]));
		
		TransformGroup tgText = new TransformGroup(t3dText);
		tgText.setUserData("TG_TEXT");
		setTransformGroupCapabilites(tgText);
		
		Text2D text = new Text2D(name, textColor, "Helvetica", fontSize, Font.BOLD);
		setShape3DCapabilites(text);
		text.setPickable(true);
//		text.setCapability(Geometry.ALLOW_INTERSECT);
		text.setRectangleScaleFactor(textScaleFactor);
		
		Point3f[] plaPts = new Point3f[2];
	    plaPts[0] = new Point3f(0.0f, 0.0f, 0.0f);
	    plaPts[1] = new Point3f((float)position[0], (float)position[1], (float)position[2]);
	    LineArray pla = new LineArray(2, LineArray.COORDINATES);
	    pla.setCoordinates(0, plaPts);
	    Appearance app = new Appearance();
	    ColoringAttributes ca = new ColoringAttributes(textColor, ColoringAttributes.SHADE_FLAT);
	    app.setColoringAttributes(ca);
	    Shape3D lineShape = new Shape3D(pla, app);
	    setShape3DCapabilites(lineShape);
	    bgText.addChild(lineShape);
		
		bgText.addChild(tgText);
		
		TransformGroup tgBillboard = new TransformGroup(new Transform3D());
		tgBillboard.setUserData("TG_BILLBOARD");
		setTransformGroupCapabilites(tgBillboard);
		tgText.addChild(tgBillboard);
		tgBillboard.addChild(text);
		Billboard billboard = new Billboard(tgBillboard, Billboard.ROTATE_ABOUT_POINT, new Point3f());
		billboard.setSchedulingBounds(bounds);
		bgText.addChild(billboard);
		
		return bgText;
	}

		
	/**
	 * Set the basic capabilities for a branch group in the system. Sets the branch group as pickable
	 * @param bg
	 */
	public static void setBranchGroupCapabilities(BranchGroup bg)
	{
		UtilitaryMethods.enablePicking(bg);
		bg.setCapability(Node.ENABLE_PICK_REPORTING);
		bg.setCapability(Group.ALLOW_CHILDREN_EXTEND);
		bg.setCapability(Group.ALLOW_CHILDREN_READ);
		bg.setCapability(Group.ALLOW_CHILDREN_WRITE);
		bg.setCapability(BranchGroup.ALLOW_DETACH);
		bg.setCapability(BranchGroup.ALLOW_BOUNDS_READ);
	}
	/**
	 * Set the basic capabilities for a shape3d in the system
	 * @param shape
	 */
	public static void setShape3DCapabilites(Shape3D shape)
	{
		shape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
		shape.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
		shape.setCapability(Node.ALLOW_BOUNDS_READ);
	}
	/**
	 * set the basic capabilities for a branch group in the system
	 * @param tg
	 */
	public static void setTransformGroupCapabilites(TransformGroup tg)
	{
		tg.setCapability(Group.ALLOW_CHILDREN_READ);
		tg.setCapability(Group.ALLOW_CHILDREN_EXTEND);
		tg.setCapability(Group.ALLOW_CHILDREN_WRITE);
		tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		tg.setCapability(Node.ENABLE_PICK_REPORTING);
		tg.setCapability(BranchGroup.ALLOW_BOUNDS_READ);
	}
	/**
	 * 
	 * @param xyzvalues
	 * @return
	 */
	public static Matrix3d rotationXYZ(double[] xyzvalues)
	{
		
		Matrix3d rotation = new Matrix3d();
		
		Transform3D xRotation = new Transform3D();
		Transform3D yRotation = new Transform3D();
		Transform3D zRotation = new Transform3D();
		
		xRotation.rotX((float)Math.toRadians(xyzvalues[0]));
		yRotation.rotY((float)Math.toRadians(xyzvalues[1]));
		zRotation.rotZ((float)Math.toRadians(xyzvalues[2]));

		zRotation.mul(yRotation);
		zRotation.mul(xRotation);
		
		zRotation.get(rotation);
		
		return rotation;
	}
	

}
